import base64
import pickle

from django.shortcuts import render

# Create your views here.
from django_redis import get_redis_connection
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView

from .serializers import *

"""
1.我们没有登录也可以将商品加入购物车  购物车的数据是放在客户端
                                放在cookie中
    登录肯定可以将商品放入购物车   购物车的数据是保存在服务器
                              mysql
                              redis(为了使用redis 的知识,)

"""

# import pickle
# import base64
# cart = {
#     '1': {'count':5,'selected':True}
# }
# # 1.将字典转换为bytes类型
# dumps = pickle.dumps(cart)
# dumps
# # 2.将bytes类型的数据重新进行base64编码
# encode = base64.b64encode(dumps)
# encode
# # 3.将编码之后的bytes类型的数据转换为字符串
# encode.decode()
# # 4.将我们的数据转换为bytes类型
# decode = base64.b64decode(encode)
# decode
# pickle.loads(decode)


class CartAPIView(APIView):

    """
    是因为我们的apiview在调用我们的http的方法前会进行认证
    我们的token过期或者伪造的话,会直接返回401
    这个时候不符合我们的业务逻辑
    我们的业务逻辑应该是:token过期或者伪造的化认为是一个匿名用户
    匿名用户的购物车数据可以放在cookie中
    对于我们编程而言,应该能够先进入到http方法中,等需要验证用户信息的是很好,在眼正

    """
    def perform_authentication(self, request):
        pass

    """
    当用户点击添加购物车按钮的时候,
    1.后端接受数据(sku_id,count,selected)
    2.验证数据(验证商品id是否有相应的商品,商品的个数)
    3.获取数据
    4.得到用户信息
    5.根据用户的信息进行判断
    6.登陆用户保存在redis中
        6.1 链接redis
        6.2 保存数据
        6.3 返回响应
    7.未登录用户保存在cookie中
        7.1 先读取cookie信息
        7.2 判断是否有购物车信息
            如果有则是加密的数据
            如果没有
        7.3 判断这个商品是否在cookie中
            如果在则 累加数据
            如果不再 则直接添加
        cart = {1:{'count':5,'selected':True}}
        7.4 将购物车数据进行加密处理

        7.5 返回响应
    """

    def post(self,request):
        # 1.后端接受数据(sku_id,count,selected)
        data = request.data
        # 2.验证数据(验证商品id是否有相应的商品,商品的个数)
        serializer = CartSerializer(data=data)
        serializer.is_valid(raise_exception=True)
        # 3.获取数据
        sku_id = serializer.validated_data.get('sku_id')
        count = serializer.validated_data.get('count')
        selected = serializer.validated_data.get('selected')
        # 4.得到用户信息
        try:
            user = request.user
        except Exception as e:
            user = None
        # 5.根据用户的信息进行判断
        if user is not None and user.is_authenticated:
            # 6.登陆用户保存在redis中
            #     6.1 链接redis
            redis_conn = get_redis_connection('cart')
            pl = redis_conn.pipeline()
            #     6.2 保存数据
            pl.hincrby('cart_%s' % user.id, sku_id, count)
            # 勾选
            if selected:
                pl.sadd('cart_selected_%s' % user.id, sku_id)

            #     6.3 返回响应
            pl.execute()
            return Response(serializer.data)
        else:
            # 7.未登录用户保存在cookie中
            #     7.1 先读取cookie信息
            cookie_str = request.COOKIES.get('cart')
            #  7.2 判断是否有购物车信息
            if cookie_str is not None:
                # 如果有则是加密的数据
                decode = base64.b64decode(cookie_str)
                # 7.2.2需要将二进制数据转换为字典
                # cookie_cart = {sku_id:{}}
                cookie_cart =  pickle.loads(decode)
            else:
                # 如果没有则定义一个空字典
                cookie_cart = {}
            #     7.3 判断这个商品是否在cookie中
            if sku_id in cookie_cart:
                #         如果在则 累加数据
                #  先获取之前的数据
                original_count = cookie_cart[sku_id]['count']
                count += original_count
            #         如果不再 则直接添加
            cookie_cart[sku_id] = {
                'count':count,
                'selected':selected
            }
            #     cart = {1:{'count':5,'selected':True}}
            #     7.4 将购物车数据进行加密处理
            dumps = pickle.dumps(cookie_cart)
            encode = base64.b64encode(dumps)
            #     7.5 返回响应
            response = Response(serializer.data)
            response.set_cookie('cart',encode.decode())
            return response
    """
    获取用户信息
    根据用户信息进行判断
    登录用户从redis中获取数据
        1.链接redis
        2.获取hash,set
    未登录用户从cookie中获取数据
        1.获取cookie数据
        2.判断cart数据
            如果有进行解密
            如果没有就是空
        3.都获取商品id,count,selected
    根据id区获取商品的详细信息
    将对象转换为字典
    """
    def get(self,request):
        try:
            user = request.user
        except Exception as e:
            user = None
        if user is not None and user.is_authenticated:
            redis_conn = get_redis_connection('cart')
            sku_id_count = redis_conn.hgetall('cart_%s' % user.id)
            selected_ids = redis_conn.smembers('cart_selected_%s' % user.id)
            cookie_cart = {}
            for sku_id, count in sku_id_count.items():
                cookie_cart[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in selected_ids
                }
        else:
            cookie_str = request.COOKIES.get('cart')
            if cookie_str is not None:
                # 如果有则是加密的数据
                decode = base64.b64decode(cookie_str)
                # 7.2.2需要将二进制数据转换为字典
                # cookie_cart = {sku_id:{}}
                cookie_cart = pickle.loads(decode)
            else:
                cookie_cart = {}

        skus = SKU.objects.filter(id__in=cookie_cart.keys())
        for sku in skus:
            sku.count = cookie_cart[sku.id]['count']
            sku.selected = cookie_cart[sku.id]['selected']
        # 序列化数据,并返回响应
        serializer = CartSKUSerializer(skus, many=True)

        return Response(serializer.data)

    def put(self,request):

        serializer = CartSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        sku_id = serializer.data.get('sku_id')
        count = serializer.data.get('count')
        selected = serializer.data.get('selected')

        try:

            user = request.user

        except Exception as e:

            user = None

        if user is not None and user.is_authenticated:
            redis_conn = get_redis_connection('cart')
            pl = redis_conn.pipeline()
            pl.hset('cart_%s' % user.id, sku_id, count)
            if selected:
                pl.sadd('cart_selected_%s' % user.id, sku_id)
            else:
                pl.srem('cart_selected_%s' % user.id,sku_id)
            pl.execute()
            return Response(serializer.data)

        else:
            cookie_str = request.COOKIES.get('cart')

            if cookie_str is not None:

                decode = base64.b64decode(cookie_str)

                cookie_cart = pickle.loads(decode)
            else:
                # 如果没有则定义一个空字典
                cookie_cart = {}
            if sku_id in cookie_cart:
                cookie_cart[sku_id] = {
                    'count': count,
                    'selected': selected
                }
            dumps = pickle.dumps(cookie_cart)
            encode = base64.b64encode(dumps)
            #     7.5 返回响应
            response = Response(serializer.data)
            response.set_cookie('cart', encode.decode())
            return response

    def delete(self,request):
        serializer = CartDeleteSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        sku_id = serializer.data.get('sku_id')
        try:

            user = request.user

        except Exception as e:

            user = None

        if user is not None and user.is_authenticated:
            redis_conn = get_redis_connection('cart')
            pl = redis_conn.pipeline()
            pl.hdel('cart_%s' % user.id, sku_id)
            pl.srem('cart_selected_%s' % user.id, sku_id)
            pl.execute()
            return Response(status=status.HTTP_204_NO_CONTENT)
        else:
            cart_str = request.COOKIES.get('cart')

            if cart_str is not None:
                cookie_cart = pickle.loads(base64.b64decode(cart_str))
            else:
                cookie_cart = {}

            response = Response(serializer.data)

            if sku_id in cookie_cart:
                del cookie_cart[sku_id]
                # 组织数据
                cookie_str = base64.b64encode(pickle.dumps(cookie_cart)).decode()
                response.set_cookie('cart', cookie_str)

            return response